import Web3 from "web3";
import abi from "./abi.json";
import useUserStore from "@/store/modules/user";

let web3 = null;
async function createWeb3() {
  web3 = await new Web3(window.ethereum);
}
createWeb3();

async function connectWallet() {
  return new Promise(async (resolve, reject) => {
    try {
      if (window.ethereum) {
        const accounts = await window.ethereum.request({
          method: "eth_requestAccounts",
        });
        let address = accounts[0];
        resolve(address);
      } else {
        reject();
        console.error("无法找到以太坊提供商。请确认钱包已安装并登录");
      }
    } catch (error) {
      reject(error);
      console.error("连接钱包失败", error);
    }
  });
}

function authorizeSignature(message) {
  return new Promise(async (resolve, reject) => {
    try {
      await connectWallet();
      const accounts = await web3.eth.getAccounts();
      // console.log("accounts---------->", accounts);
      const signature = await web3.eth.personal.sign(message, accounts[0], "");
      // console.log("授权签名成功:", signature);
      resolve({ flag: true, sign: signature });
    } catch (error) {
      console.log("🚀 authorizeSignature 授权签名发生错误:", error);
      reject(error);
    }
  });
}

// 查询交易状态
const queryPayment = async (resolve, reject, transactionHash) => {
  const web3 = await new Web3(window.ethereum);
  while (1) {
    try {
      let state = await web3.eth.getTransactionReceipt(transactionHash);
      await setTimeout(() => {}, 1000);
      if (state == null) {
        continue;
      }
      console.log("state---------->", state);
      if (Number(state.status) === 1) {
        resolve(transactionHash);
        break;
      } else {
        reject(false);
        break;
      }
    } catch (e) {
      reject(e);
      break;
    }
  }
};

// 代币授权
const approveToken = (contract_address, recipient, quantity, ownerAddress) => {
  return new Promise(async (resolve, reject) => {
    try {
      let contract = await new web3.eth.Contract(abi, contract_address);
      quantity = +quantity * 10 ** 18;
      console.log(quantity, "quantity");
      const result = await contract.methods.approve(recipient, quantity).send({
        gas: 5000000,
        from: ownerAddress,
      });
      console.log(result, "授权成功");
      resolve(result);
    } catch (err) {
      console.log(err, "授权失败");
      reject(err);
    }
  });
};

// 置换
const exchange = (contract_address, amount, ownerAddress) => {
  return new Promise(async (resolve, reject) => {
    try {
      let contract = await new web3.eth.Contract(abi, contract_address);
      const result = await contract.methods.exchange(amount * 10 ** 18).send({
        from: ownerAddress,
        gas: 5000000,
      });
      queryPayment(resolve, reject, result.transactionHash);
    } catch (err) {
      console.log("🚀  exchange  置换失败:", error);
      reject(err);
    }
  });
};

//  购买节点
const buyNode = (contractAddress, index, ownerAddress) => {
  return new Promise(async (resolve, reject) => {
    try {
      const contract = await new web3.eth.Contract(abi, contractAddress);
      if (!ownerAddress) {
        const accounts = await web3.eth.getAccounts();
        ownerAddress = accounts[0];
      }
      const result = await contract.methods.buyNode(index).send({
        from: ownerAddress,
        gas: 5000000,
      });
      console.log("充值结果---------->", result);
      queryPayment(resolve, reject, result.transactionHash);
    } catch (error) {
      console.log("🚀  buyNode  购买节点失败:", error);
      reject(error);
    }
  });
};

// 发起指定代币转账
const transfer = (to_address, amount_base, contract_address, contract_abi) => {
  return new Promise(async (resolve, reject) => {
    try {
      const contract = await new web3.eth.Contract(
        JSON.parse(
          `[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]`
        ),
        contract_address
      );
      const accounts = await web3.eth.getAccounts();
      let ownerAddress = accounts[0];
      let amount = amount_base * 10 ** 18;
      const transfer_result = await contract.methods.transfer(
        to_address,
        amount
      );
      console.log("transfer_result---------->", transfer_result);
      const result = await transfer_result
        .send({
          from: ownerAddress,
        })
        .then((res) => {
          console.log("send res---------->", res);
          queryPayment(resolve, reject, res.transactionHash);
        });
    } catch (error) {
      console.log("🚀  transfer  转账失败:", error);
      reject(error);
    }
  });
};
// 查询代币余额
const queryBalance = (contractAddress) => {
  return new Promise(async (resolve, reject) => {
    const userStore = useUserStore();
    const tokenContract = new web3.eth.Contract(abi, contractAddress);
    tokenContract.methods.balanceOf(userStore.address).call()
      .then(async balance => {
        const balanceInToken = Number(balance)/(10**18); // 根据小数位数调整余额
        resolve(balanceInToken);
      })
      .catch(error => {
        reject(error);
      });
  });
}
// 代币授权
// 根据地址获取代币金额
const authorize =  async(obj)=> {

  // 调用的合约对象 obj.name
  // 钱包地址 obj.fromAccount
  // 收款地址 obj.toAccount
  // 价格 obj.quantity
  // 合约地址 obj.contract
  // 合约abi obj.abi
  return new Promise(async (resolve, reject) => {
    
    // 指定的合约对象是否存在,不存在则去创建
    let walletAddress;
    if (!web3) {
      console.log("没有合约对象");
      await createWeb3();
    } else {
      console.log("有合约对象");
    }
    console.log('obj.name', obj.name);

    console.log('obj.fromAccount', obj.fromAccount);

    // 没有指定的钱包地址则查询当前连接的钱包
    if (obj.fromAccount) {
      walletAddress = obj.fromAccount;
    } else {
      const userStore = useUserStore();
      walletAddress = userStore.address;
    }

    // 小数位
    const decimal = await specified_decimals(obj);
    console.log(decimal);

    // 计算价格
    let { quantity } = obj;
    if (decimal && decimal > 6) {
      quantity *= 1000000;
      // console.log(decimal - 6);
      for (var i = 0; i < 18 - 6; i++) {
        quantity += "0";
      }
    } else {
      let sb = 1;
      for (var i = 0; i < (18 || 0); i++) {
        sb += "0";
      }
      quantity *= sb;
    }

    // 获取以太坊网络上的 Gas 价格
    let gasPrice = await getGasPrice();
    console.log('Gas 价格', gasPrice);
    const contract = await new web3.eth.Contract(obj.abi, obj.toAccount);

    /* approve 方法是在用户或者其他智能合约准备进行
    代币转移之前调用的，用以授权所需的代币数量 */
    const obj1 = await contract.methods.approve(
      obj.authorizeAccount,
      quantity.toString()
    )
    console.log('obj1obj1obj1obj1', obj1);

    // let gas = null;
    // const gas = await obj1
    //   .estimateGas({
    //     from: walletAddress,
    //     gasPrice: gasPrice,
    //   })
    // console.log('aaaaaaaaa', gas);
    try {


      const result = await obj1.send(
        {
          from: walletAddress,
          gas: 3000000,
          gasPrice: gasPrice,
        },
        async function (error, transactionHash) {
          if (!error) {
            console.log('resolveresolveresolve');
            // 成功执行时返回订单号
            queryPayment(resolve, reject, transactionHash);
          } else {
            // 失败执行
            console.log('授权失败授权失败授权失败授权失败授权失败');

            reject(error);
          }
        }
      )
      console.log('授权成功', result);
      resolve(result);
    } catch (err) {
      console.log('授权失败', err);

      reject(err);
    }
  });
}
// 获取以太坊网络上的 Gas 价格
const getGasPrice = async()=> {
  return await web3.eth.getGasPrice().then((_gasPrice) => {
    // console.log("_gasPrice--------->", _gasPrice);
    return _gasPrice;
  });
}
// 定义一个异步函数gePayment，用于调用合约的payment方法
const gePayment = async(contract_address, contract_abi, obj)=> {
  if (!web3) {
    await createWeb3();
  }
  const userStore = useUserStore();
  let abis = JSON.parse(contract_abi)
  const contract = await new web3.eth.Contract(abis, contract_address);
    //payment（ orderId:订单号  address：代币合约地址  [to_address]：收款地址  [num]:数量  lastTime：时间戳）
    console.log(obj);
    
  return await contract.methods.payment(obj.order_id, obj.contract_address, obj.addresses, obj.amounts, obj.last_time).send(
    {
      from: userStore.address,
    }
  );
}
const geTauthorizeBalance = async(contract_address, collect_contract, contract_abi)=> {
  if (!web3) {
    await createWeb3();
  }
  let abis = JSON.parse(contract_abi)

  const contract = await new web3.eth.Contract(abis, contract_address);
  // console.log(contract.methods.allowance);
  const userStore = useUserStore();
  return await contract.methods.allowance(userStore.address, collect_contract).call();
}
 // 查询代币小数位
 const specified_decimals = async(obj)=> {
  // 调用的合约对象 obj.name
  // 钱包地址 obj.fromAccount
  // 合约地址 obj.contract
  // 合约abi obj.abi
  // console.log(obj)
  let walletAddress;
  let num;
  // 指定的合约对象是否存在,不存在则去创建
  if (!web3) {
    await createWeb3();
  }
  // 没有指定的钱包地址则查询当前连接的钱包
  if (obj.address) {
    walletAddress = obj.address;
  } else {
    const userStore = useUserStore();
    walletAddress = userStore.address;
  }
  // console.log(this[obj.name].methods.decimals().call({ from: walletAddress }));
  /* decimals() 方法通常用于智能合约中的代币信息查询操作，
  用户可以使用它来查询代币的小数位数，以确定代币的精度 */
  const contract = await new web3.eth.Contract(obj.abi, obj.toAccount);
  num = await contract.methods.decimals().call();
  return num;
}
export default {
  connectWallet,
  approveToken,
  exchange,
  buyNode,
  authorizeSignature,
  transfer,
  authorize,
  gePayment,
  getGasPrice,
  geTauthorizeBalance,
  queryBalance
};
